/*
 * Serum
 *
 * @license      GNU Lesser General Public Licence see LICENCE-LGPL file or http://www.gnu.org/licenses/lgpl.html
 */

/**
 * Serum Selector
 *
 * Used to change modules, controllers and actions.
 */
Serum.Selector = function() {
    var _instance = null;
    var _modules  = {};

     var __construct = function() {
        return {
            /**
             * Modules list
             */
            modules:    [],

            /**
             * Current module
             */
            module:     'Core',

            /**
             * Current controller
             */
            controller: 'Index',

            /**
             * Current action
             */
            action:     'index',

            /**
             * Current language
             */
            language:   'fr_FR',

            /**
             * Other params (&)
             */
            getParams:  {},

            /**
             * Root URL for server requests
             */
            rootUrl:    '/',

            /**
             * Root URL for media
             */
            mediaUrl:    '/',

            /**
             * Returns URL for server requests.
             *
             * @param   {String}    type    Request type (json, index)
             * @return  {String}            Request URL
             */
            requestUrl: function(type) {
                if (typeof type === 'undefined') {
                    type = 'json';
                }

                return this.rootUrl + type + '.php';
            },

            /**
             * Sets base Url.
             *
             * @para        {String}        baseUrl
             */
            setBaseUrl: function(url) {
                this.rootUrl    = url + 'serum/';
                this.mediaUrl   = url + 'media/';
                this.skinUrl    = url + 'skin/';
            },

            /**
             * Returns current module object
             *
             * Returns Serum.Module.Base if current module doesn't exists.
             *
             * @return  {Serum.Module.Abstract}     Current module object
             */
            currentModule: function() {
                if (typeof _modules[this.module] === 'undefined') {
                    var moduleName          = new String(this.module).ucfirst();
                    _modules[this.module]   = (typeof Serum.Module[moduleName] === 'function') ? new Serum.Module[moduleName] : new Serum.Module.Base();
                }

                return _modules[this.module];
            },

            /**
             * Defines new selector.
             *
             * @param   {Object}    override            Parameters to be changed
             * @param   {Boolean}   deleteAndParams     If true, deletes former & params in URL
             */
            set: function(override, deleteAndParams) {
                var param = null;

                if (typeof deleteAndParams === 'undefined') {
                    deleteAndParams = true;
                }

                if (typeof override !== 'object') {
                    override = {};
                }

                var fireModule = false, fireController = false, fireAction = false, fireLanguage = false;

                if ((typeof override['module'] !== 'undefined')) {
                    this.module     = override['module'];
                    delete override['module'];
                    fireModule      = true;
                    fireController  = true;
                    fireAction      = true;
                    fireLanguage    = true;
                }

                if ((typeof override['controller'] !== 'undefined')) {
                    this.controller = override['controller'];
                    delete override['controller'];
                    fireController  = true;
                    fireAction      = true;
                    fireLanguage    = true;
                }

                if ((typeof override['action'] !== 'undefined')) {
                    this.action     = override['action'];
                    delete override['action'];
                    fireAction      = true;
                    fireLanguage    = true;
                }

                if ((typeof override['language'] !== 'undefined')) {
                    this.language   = override['language'];
                    delete override['language'];
                    fireLanguage    = true;
                }

                if (deleteAndParams) {
                    this.getParams = {};
                }

                for (param in override) {
                    if (typeof override[param] !== 'function' && override[param] !== null) {
                        this.getParams[param] = override[param];
                    }
                }

                var supParams = '';
                for (param in this.getParams) {
                    if ((typeof this.getParams[param] !== 'function') && (typeof this.getParams[param] !== 'undefined')) {
                        supParams += '&' + param + '=' + this.getParams[param];
                    }
                }

                document.location.hash = this.method() + supParams;


                if (fireModule) {
                    Serum.App.get().eventListener.fireEvent('modulechanged');
                }

                if (fireController) {
                    Serum.App.get().eventListener.fireEvent('controllerchanged');
                }

                if (fireAction) {
                    Serum.App.get().eventListener.fireEvent('actionchanged');
                }

                if (fireLanguage && fireAction === false) {
                    Serum.App.get().eventListener.fireEvent('languagechanged');
                }
            },

            /**
             * Loads parameters from current URL.
             */
            load: function() {                
                if (document.location.hash !== '') {
                    var match = document.location.hash.match(new RegExp("([a-zA-Z0-9_\.]+)~?([a-zA-Z0-9_]*):?([a-zA-Z0-9_]*):?([A-Z_]*)"));

                    if (typeof match[1] !== 'undefined' && match[1] !== '') {
                        this.module     = match[1];
                    }

                    if (typeof match[2] !== 'undefined' && match[2] !== '') {
                        this.controller = match[2];
                    }

                    if (typeof match[3] !== 'undefined' && match[3] !== '') {
                        this.action     = match[3];
                    }

                    if (typeof match[4] !== 'undefined' && match[4] !== '') {
                        this.language   = match[4];
                    }

                    var _params = document.location.hash.split('&');

                    if (_params.length > 1) {
                        for (var param in _params) {
                            if (param > 0) {
                                var splittedParam                   = (_params[param]).split('=');
                                this.getParams[splittedParam[0]]    = splittedParam[1];
                            }
                        }
                    }
                }
            },

            /**
             * Returns method attribute for requests.
             *
             * Format module~controller:action
             *
             * @param   {Object}    override    Overrided parameters to put in method. Doesn't modify current selector.
             */
            method: function(override) {
                if (typeof override !== 'object') {
                    override = {};
                }

                var module      = ((typeof override['module'] !== 'undefined'))     ? override['module']        : this.module;
                var controller  = ((typeof override['controller'] !== 'undefined')) ? override['controller']    : this.controller;
                var action      = ((typeof override['action'] !== 'undefined'))     ? override['action']        : this.action;
                var language    = null;
                
                if (typeof override['language'] !== 'undefined') {
                    var splittedLanguage    = override['language'].split('_');
                    language    = splittedLanguage[0].toLowerCase() + splittedLanguage[1].toUpperCase();
                } else {
                    language    = this.language;
                }

                return module + '~' + controller + ':' + action + ':' + language;
            },

            /**
             * Loads modules list
             *
             * @param   {Object}    modules
             */
            loadModules: function(modules) {
                for (var _package in modules) {
                    if (typeof _package === 'object') {
                        for(var module in _package) {
                            this.modules.push(module);
                        }
                    }
                }
            }
        }
    };

    return {
        /**
         * Returns instance
         *
         * @return {Serum.Selector}     Instance
         */
        get: function() {
            if (_instance === null) {
                _instance = __construct();
            }
            return _instance;
        }
    };
}();